#include <myFs/bitmap.h>
#include <stdexcept>

namespace myFs {
namespace basic {

using size_t = std::uint32_t;

Bitmap::Bitmap() = default;
Bitmap::Bitmap(void* baseptr, void* targetptr, size_t blocknum, size_t blocksize)
    : m_bitset(static_cast<size_t*>(baseptr), blocknum), m_targetptr(targetptr), m_blocksize(blocksize){};

void Bitmap::init(void* baseptr, void* targetptr, size_t blocknum, size_t blocksize) {
    m_bitset.init(static_cast<size_t*>(baseptr), blocknum);
    m_targetptr = targetptr;
    m_blocksize = blocksize;
}

size_t Bitmap::size() const { return m_bitset.size(); }

size_t Bitmap::usedBlock() const { return m_bitset.used(); }  ///< 置1的bit数

size_t Bitmap::freeBlock() const { return size() - usedBlock(); }  ///< 置0的bit数

bool Bitmap::hasAlloc(size_t inum) const { return m_bitset.at(inum); }

size_t Bitmap::alloc(size_t blknum) {
    if (blknum == 0) return 0;
    for (size_t i = 0; i < size(); i++) {
        size_t cnt = 0;
        if (!m_bitset.at(i)) {
            for (size_t j = i; j < size(); j++) {
                if (!m_bitset.at(j))
                    ++cnt;
                else {
                    i = j;
                    break;
                }
                if (cnt == blknum) {
                    for (size_t k = i; k <= j; k++) {
                        m_bitset.set(k);
                    }
                    return i;
                }
            }
        }
    }
    throw ::std::runtime_error("no more block to alloc");
}

void Bitmap::dealloc(size_t blkid, size_t blknum) {
    if (blknum == 0) return;
    while (blknum--) {
        if (blkid >= size()) return;
        m_bitset.reset(blkid++);
    }
}

void* Bitmap::convertToAddr(size_t bnum) const { return (char*)m_targetptr + (bnum * m_blocksize); }
size_t Bitmap::blocksize() const { return m_blocksize; }
}  // namespace basic
}  // namespace myFs